﻿#include "Windows7PrinterDriverInstaller.h"
#include "IVirtualPortMonitorInstaller.h"
extern void AppendErrorLogToFile(const char* log);
extern void AppendInfoLogToFile(const char* log);
int CalcCombineTwoStrNeedMallocSize(LPWSTR str1, LPWSTR str2);
void DestroyDriverConfigInfo(DRIVER_INFO_6W* pDriverInfo6W);

DWORD DriverAttributeDriverNameInit(DRIVER_INFO_6W* pDriverInfoW, LPWSTR szDriverPath, LPWSTR szArg);
DWORD DriverAttributeMonitorNameInit(DRIVER_INFO_6W* pDriverInfoW, LPWSTR szDriverPath, LPWSTR szArg);
DWORD DriverAttributeDefaultDataTypeInit(DRIVER_INFO_6W* pDriverInfoW, LPWSTR szDriverPath, LPWSTR szArg);
DWORD DriverAttributeDriverPathInit(DRIVER_INFO_6W* pDriverInfoW, LPWSTR szDriverPath, LPWSTR szArg);
DWORD DriverAttributeConfigFileInit(DRIVER_INFO_6W* pDriverInfoW, LPWSTR szDriverPath, LPWSTR szArg);
DWORD DriverAttributeDataFileInit(DRIVER_INFO_6W* pDriverInfoW, LPWSTR szDriverPath, LPWSTR szArg);
DWORD DriverAttributeHelpFileInit(DRIVER_INFO_6W* pDriverInfoW, LPWSTR szDriverPath, LPWSTR szArg);
DWORD DriverAttributeDependentFilesInit(DRIVER_INFO_6W* pDriverInfoW, LPWSTR szDriverPath, LPWSTR szArg);

typedef struct {
	LPWSTR   pszMethod;
	DWORD(*pfn)	(DRIVER_INFO_6W* pDriverInfoW, LPWSTR szDriverPath, LPWSTR szArg);
	LPWSTR* szArg;
}	PRINTER_ATTRIBUTE_INIT_METHOD, * PDRIVER_ATTRIBUTE_INIT_METHOD;

PRINTER_ATTRIBUTE_INIT_METHOD  DriverAttributeInitMethod[] = {
						{(LPWSTR)L"DriverMonitorNameAttributeInit", DriverAttributeMonitorNameInit, &IVirtualPortMonitorInstaller::VirtualPortMonitorName},
						{(LPWSTR)L"DriverDefaultDataTypeAttributeInit", DriverAttributeDefaultDataTypeInit, &IVirtualPrinterDriverInstaller::DriverPrinterDefaultDataTypeName},
						{(LPWSTR)L"DriverPathAttributeInit", DriverAttributeDriverPathInit, &IVirtualPrinterDriverInstaller::DriverFileName},
						{(LPWSTR)L"DriverConfigFileAttributeInit", DriverAttributeConfigFileInit, &IVirtualPrinterDriverInstaller::DriverUIFileName},
						{(LPWSTR)L"DriverDataFileAttributeInit", DriverAttributeDataFileInit,&IVirtualPrinterDriverInstaller::DriverDataFileName},
						{(LPWSTR)L"DriverHelpFileAttributeInit", DriverAttributeHelpFileInit, &IVirtualPrinterDriverInstaller::DriverHelpFileName},
						{(LPWSTR)L"DriverDependentFilesAttributeInit", DriverAttributeDependentFilesInit, &IVirtualPrinterDriverInstaller::DriverPrinterDependentFilesName},
						{NULL, NULL}
};

Windows7PrinterDriverInstaller::Windows7PrinterDriverInstaller()
{

}

Windows7PrinterDriverInstaller::~Windows7PrinterDriverInstaller()
{

}

bool Windows7PrinterDriverInstaller::VirtualPrinterDriverInstall(LPWSTR szDriverName)
{
	BOOL bExecuteResult = FALSE;
	DRIVER_INFO_6W* driver_info = GenerateDriverConfigInfo(szDriverName);
	if (driver_info != NULL) {
		bExecuteResult = AddPrinterDriverW(NULL, 6, (LPBYTE)driver_info);

		DestroyDriverConfigInfo(driver_info);
		driver_info = NULL;
		AppendErrorLogToFile("VirtualPrinterDriverInstall(): GenerateDriverConfigInfo Error");
	}

	return bExecuteResult;
}

int Windows7PrinterDriverInstaller::GetSystemPrinterDriverInstallDirectory(BYTE** path)
{
	BOOL bExcuteResult = FALSE;
	DWORD dwRealPathBytesSize = 0;

	*path = NULL;

	WCHAR* szDriverPath = new WCHAR[MAX_PATH + 1];
	if (szDriverPath != NULL) {
		dwRealPathBytesSize = sizeof(WCHAR) * MAX_PATH;
		memset(szDriverPath, 0, dwRealPathBytesSize);
		bExcuteResult = GetPrinterDriverDirectoryW(NULL, NULL, 1, (LPBYTE)szDriverPath, dwRealPathBytesSize, &dwRealPathBytesSize);

		if (bExcuteResult) {
			*path = (LPBYTE)szDriverPath;
		}
		else {
			AppendErrorLogToFile("GetSystemPrinterDriverInstallDirectory(): GetPrinterDriverDirectoryW Error");
			delete[] szDriverPath;
			szDriverPath = NULL;
			dwRealPathBytesSize = 0;
		}
	}

	return dwRealPathBytesSize;
}

DRIVER_INFO_6W* Windows7PrinterDriverInstaller::GenerateDriverConfigInfo(LPWSTR szDriverName)
{
	DWORD dwNeedAllocLen = 0;
	BYTE* szDriverInstallPath = NULL;
	BYTE* pbSysDirectorPath = NULL;
	DRIVER_INFO_6W* pDriverInfo = NULL;

	DWORD dwLen = GetSystemPrinterDriverInstallDirectory(&pbSysDirectorPath);
	if (pbSysDirectorPath != NULL) {
		pDriverInfo = (DRIVER_INFO_6W*)malloc(sizeof(DRIVER_INFO_6W));
		if (pDriverInfo != NULL) {
			do {
				memset(pDriverInfo, 0, sizeof(DRIVER_INFO_6W));
				pDriverInfo->cVersion = 3;
				pDriverInfo->dwlDriverVersion = 0x0001000000000000U;
				if (DriverAttributeDriverNameInit(pDriverInfo, (LPWSTR)pbSysDirectorPath, szDriverName) < 0){
					DestroyDriverConfigInfo(pDriverInfo);
					pDriverInfo = NULL;

					AppendErrorLogToFile("DriverAttributeDriverNameInit(): Init Error Ret < 0");
					break;
				}

				for (DWORD dwEnumIndex = 0; DriverAttributeInitMethod[dwEnumIndex].pfn != NULL; dwEnumIndex++) {
					DWORD bExcuteResult = DriverAttributeInitMethod[dwEnumIndex].pfn(pDriverInfo, (LPWSTR)pbSysDirectorPath, *DriverAttributeInitMethod[dwEnumIndex].szArg);
					if (bExcuteResult < 0) {
						DestroyDriverConfigInfo(pDriverInfo);
						pDriverInfo = NULL;

						AppendErrorLogToFile("DriverAttributeInitMethod(): Init Error Ret < 0");
						break;
					}
				}
			} while (false);
		}

		delete[] pbSysDirectorPath;
		pbSysDirectorPath = NULL;
	}

	return pDriverInfo;
}

int CalcCombineTwoStrNeedMallocSize(LPWSTR str1, LPWSTR str2)
{
	DWORD dwCombineTwoStrNeedBytesSize = 0;
	const size_t EXTRA_SPACE = 10;

	if (str1 != NULL) {
		dwCombineTwoStrNeedBytesSize += wcslen(str1);
	}

	if (str2 != NULL) {
		dwCombineTwoStrNeedBytesSize += wcslen(str2);
	}

	dwCombineTwoStrNeedBytesSize += EXTRA_SPACE;

	return dwCombineTwoStrNeedBytesSize * sizeof(wchar_t);
}

DWORD DriverAttributeDriverNameInit(DRIVER_INFO_6W* pDriverInfoW, LPWSTR szDriverPath, LPWSTR szArg) {
	DWORD dwNeedAllocSize = CalcCombineTwoStrNeedMallocSize(szDriverPath, szArg);
	pDriverInfoW->pName = (LPWSTR)malloc(dwNeedAllocSize);
	if (pDriverInfoW->pName != NULL) {
		memset(pDriverInfoW->pName, 0, dwNeedAllocSize);
		wcsncpy(pDriverInfoW->pName, szArg, (dwNeedAllocSize/ sizeof(WCHAR)) - 1);
	}
	else {
		AppendErrorLogToFile("DriverAttributeDriverNameInit(): malloc Memory Error");
	}

	return pDriverInfoW->pName == NULL ? -1 : 1;
}

DWORD DriverAttributeMonitorNameInit(DRIVER_INFO_6W* pDriverInfoW, LPWSTR szDriverPath, LPWSTR szArg) {
	int dwNeedAllocSize = CalcCombineTwoStrNeedMallocSize((LPWSTR)szDriverPath, IVirtualPortMonitorInstaller::VirtualPortMonitorName);
	pDriverInfoW->pMonitorName = (LPWSTR)malloc(dwNeedAllocSize);
	if (pDriverInfoW->pMonitorName != NULL) {
		memset(pDriverInfoW->pMonitorName, 0, dwNeedAllocSize);
		wcsncpy(pDriverInfoW->pMonitorName, (LPWSTR)IVirtualPortMonitorInstaller::VirtualPortMonitorName, (dwNeedAllocSize / sizeof(WCHAR)) - 1);
	}
	else {
		AppendErrorLogToFile("DriverAttributeMonitorNameInit(): malloc Memory Error");
	}

	return pDriverInfoW->pMonitorName == NULL ? -1 : 1;
}

DWORD DriverAttributeDefaultDataTypeInit(DRIVER_INFO_6W* pDriverInfoW, LPWSTR szDriverPath, LPWSTR szArg) {
	int dwNeedAllocSize = CalcCombineTwoStrNeedMallocSize((LPWSTR)szDriverPath, szArg);
	pDriverInfoW->pDefaultDataType = (LPWSTR)malloc(dwNeedAllocSize);
	if (pDriverInfoW->pDefaultDataType != NULL) {
		memset(pDriverInfoW->pDefaultDataType, 0, dwNeedAllocSize);
		wcsncpy(pDriverInfoW->pDefaultDataType, szArg, (dwNeedAllocSize / sizeof(WCHAR)) - 1);
	}
	else {
		AppendErrorLogToFile("malloc Memory Error");
	}

	return pDriverInfoW->pDefaultDataType == NULL ? -1 : 1;
}

DWORD DriverAttributeDriverPathInit(DRIVER_INFO_6W* pDriverInfoW, LPWSTR szDriverPath, LPWSTR szArg) {
	int dwNeedAllocSize = CalcCombineTwoStrNeedMallocSize((LPWSTR)szDriverPath, szArg) + wcslen(L"//") * sizeof(WCHAR);
	pDriverInfoW->pDriverPath = (LPWSTR)malloc(dwNeedAllocSize);
	if (pDriverInfoW->pDriverPath != NULL) {
		DWORD dwNeedCopyCount = (dwNeedAllocSize / sizeof(WCHAR)) - 1;
		memset(pDriverInfoW->pDriverPath, 0, dwNeedAllocSize);
		wcsncpy(pDriverInfoW->pDriverPath, (LPWSTR)szDriverPath, dwNeedCopyCount);
		dwNeedCopyCount -= wcslen(szDriverPath);
		wcsncat(pDriverInfoW->pDriverPath, (LPWSTR)L"\\" , dwNeedCopyCount);
		dwNeedCopyCount -= wcslen(L"\\");
		wcsncat(pDriverInfoW->pDriverPath, (LPWSTR)szArg , dwNeedCopyCount);
		dwNeedCopyCount -= wcslen(szArg);
	}
	else {
		AppendErrorLogToFile("DriverAttributeDriverPathInit(): malloc Memory Error");
	}

	return pDriverInfoW->pDriverPath == NULL ? -1 : 1;
}

DWORD DriverAttributeConfigFileInit(DRIVER_INFO_6W* pDriverInfoW, LPWSTR szDriverPath, LPWSTR szArg) {
	int dwNeedAllocSize = CalcCombineTwoStrNeedMallocSize((LPWSTR)szDriverPath, szArg) + wcslen(L"//") * sizeof(WCHAR);
	pDriverInfoW->pConfigFile = (LPWSTR)malloc(dwNeedAllocSize);
	if (pDriverInfoW->pConfigFile != NULL) {
		DWORD dwNeedCopyCount = (dwNeedAllocSize / sizeof(WCHAR)) - 1;
		memset(pDriverInfoW->pConfigFile, 0, dwNeedAllocSize);
		wcsncpy(pDriverInfoW->pConfigFile, (LPWSTR)szDriverPath, wcslen(szDriverPath));
		dwNeedCopyCount -= wcslen(szDriverPath);
		wcsncat(pDriverInfoW->pConfigFile, (LPWSTR)L"\\", wcslen(L"\\"));
		dwNeedCopyCount -= wcslen(L"\\");
		wcsncat(pDriverInfoW->pConfigFile, (LPWSTR)szArg, wcslen(szArg));
		dwNeedCopyCount -= wcslen(szArg);
	}
	else {
		AppendErrorLogToFile("DriverAttributeConfigFileInit(): malloc Memory Error");
	}

	return pDriverInfoW->pConfigFile == NULL ? -1 : 1;
}

DWORD DriverAttributeDataFileInit(DRIVER_INFO_6W* pDriverInfoW, LPWSTR szDriverPath, LPWSTR szArg) {
	int dwNeedAllocSize = CalcCombineTwoStrNeedMallocSize((LPWSTR)szDriverPath, szArg) + wcslen(L"//") * sizeof(WCHAR);
	pDriverInfoW->pDataFile = (LPWSTR)malloc(dwNeedAllocSize);
	if (pDriverInfoW->pDataFile != NULL) {
		DWORD dwNeedCopyCount = (dwNeedAllocSize / sizeof(WCHAR)) - 1;
		memset(pDriverInfoW->pDataFile, 0, dwNeedAllocSize);
		wcsncpy(pDriverInfoW->pDataFile, (LPWSTR)szDriverPath, wcslen(szDriverPath));
		dwNeedCopyCount -= wcslen(szDriverPath);
		wcsncat(pDriverInfoW->pDataFile, (LPWSTR)L"\\", wcslen(L"\\"));
		dwNeedCopyCount -= wcslen(L"\\");
		wcsncat(pDriverInfoW->pDataFile, (LPWSTR)szArg, wcslen(szArg));
		dwNeedCopyCount -= wcslen(szArg);
	}
	else {
		AppendErrorLogToFile("DriverAttributeDataFileInit(): malloc Memory Error");
	}

	return pDriverInfoW->pDataFile == NULL ? -1 : 1;
}

DWORD DriverAttributeHelpFileInit(DRIVER_INFO_6W* pDriverInfoW, LPWSTR szDriverPath, LPWSTR szArg) {
	int dwNeedAllocSize = CalcCombineTwoStrNeedMallocSize((LPWSTR)szDriverPath, szArg) + wcslen(L"//") * sizeof(WCHAR);
	pDriverInfoW->pHelpFile = (LPWSTR)malloc(dwNeedAllocSize);
	if (pDriverInfoW->pHelpFile != NULL) {
		DWORD dwNeedCopyCount = (dwNeedAllocSize / sizeof(WCHAR)) - 1;
		memset(pDriverInfoW->pHelpFile, 0, dwNeedAllocSize);
		wcsncpy(pDriverInfoW->pHelpFile, (LPWSTR)szDriverPath, wcslen(szDriverPath));
		dwNeedCopyCount -= wcslen(szDriverPath);
		wcsncat(pDriverInfoW->pHelpFile, (LPWSTR)L"\\", wcslen(L"\\"));
		dwNeedCopyCount -= wcslen(L"\\");
		wcsncat(pDriverInfoW->pHelpFile, (LPWSTR)szArg, wcslen(szArg));
		dwNeedCopyCount -= wcslen(szArg);
	}
	else {
		AppendErrorLogToFile("DriverAttributeHelpFileInit(): malloc Memory Error");
	}

	return pDriverInfoW->pHelpFile == NULL ? -1 : 1;
}

DWORD DriverAttributeDependentFilesInit(DRIVER_INFO_6W* pDriverInfoW, LPWSTR szDriverPath, LPWSTR szArg) {
	int dwNeedAllocSize = CalcCombineTwoStrNeedMallocSize((LPWSTR)szDriverPath, szArg) + wcslen(L"//") * sizeof(WCHAR);
	pDriverInfoW->pDependentFiles = (LPWSTR)malloc(dwNeedAllocSize);
	if (pDriverInfoW->pDependentFiles != NULL) {
		DWORD dwNeedCopyCount = (dwNeedAllocSize / sizeof(WCHAR)) - 1;
		memset(pDriverInfoW->pDependentFiles, 0, dwNeedAllocSize);
		wcsncpy(pDriverInfoW->pDependentFiles, (LPWSTR)szDriverPath, wcslen(szDriverPath));
		dwNeedCopyCount -= wcslen(szDriverPath);
		wcsncat(pDriverInfoW->pDependentFiles, (LPWSTR)L"\\", wcslen(L"\\"));
		dwNeedCopyCount -= wcslen(L"\\");
		wcsncat(pDriverInfoW->pDependentFiles, (LPWSTR)szArg, wcslen(szArg));
		dwNeedCopyCount -= wcslen(szArg);
	}
	else {
		AppendErrorLogToFile("DriverAttributeDependentFilesInit(): malloc Memory Error");
	}

	return pDriverInfoW->pDependentFiles == NULL ? -1 : 1;
}

void DestroyDriverConfigInfo(DRIVER_INFO_6* pDriverInfo6W)
{
	if (pDriverInfo6W == NULL) {
		return;
	}

	if (pDriverInfo6W->pName != NULL) {
		free(pDriverInfo6W->pName);
		pDriverInfo6W->pName = NULL;
	}

	if (pDriverInfo6W->pDriverPath != NULL) {
		free(pDriverInfo6W->pDriverPath);
		pDriverInfo6W->pDriverPath = NULL;
	}

	if (pDriverInfo6W->pConfigFile != NULL) {
		free(pDriverInfo6W->pConfigFile);
		pDriverInfo6W->pConfigFile = NULL;
	}

	if (pDriverInfo6W->pDataFile != NULL) {
		free(pDriverInfo6W->pDataFile);
		pDriverInfo6W->pDataFile = NULL;
	}

	if (pDriverInfo6W->pHelpFile != NULL) {
		free(pDriverInfo6W->pHelpFile);
		pDriverInfo6W->pHelpFile = NULL;
	}

	if (pDriverInfo6W->pDependentFiles != NULL) {
		free(pDriverInfo6W->pDependentFiles);
		pDriverInfo6W->pDependentFiles = NULL;
	}

	free(pDriverInfo6W);
	pDriverInfo6W = NULL;
}